Historically, computer software applications were self-contained, and were sometimes referred to as centralized or monolithic. This meant that a software application consisted of a single executable file or several executable files that were chained together. In general, all of the executable files associated with an application were only used for that particular application.
However, with the introduction of libraries, code re-use and client-server models for computing, the component model of computing evolved. With the rise of object-oriented programming languages and client-server computing, the component model led to distributed architectures, where the focus shifted to the management of components and widely dispersed computing resources.
Unlike the centralized model noted above, where an executable file was only intended to be used for a particular application, with the component model, programs are written as software components (sometimes hereinafter referred to as “components”) that can be assembled into applications. A component can be reused by many programmers and different applications, saving software coding time, among other advantages.
For an application to use a component (or any distributed piece of software), the application communicates with the component through the component's interface. Typically, an interface requires certain inputs and provides certain outputs. If an application is receiving information from a component, the application must understand what the information means. If an application is providing information to a component, the application must provide information in a manner that the component is expecting.
When an application is written, the programmer codes the application knowing what information must be passed to each component and the programmer understands what information each component returns. However, if, for example, an application uses components from a graphics library, and if the components are updated, but the application is not updated, the application may no longer function properly, or at all, if the updated versions of the components now either pass different information (or a different type of information) to the application or require different information from the application.
Typically, when a newer version of a component is introduced, such that it now requires or sends information different from the previous version, each application that uses the component is modified through hand-coding, in a one-off fashion, to accommodate the change to the component. In other words, a new version of a component has historically required a corresponding upgrade to each application that uses the component and then redeployment. Amending an application's code in this manner is time. consuming, and therefore expensive. It is also error-prone. If many applications use the same components, all of the applications must be updated, or else risk not working properly. Moreover, there is typically no record (and no standard for such a record) indicating what changes were made or how the changes were made. Accordingly, it is often difficult for anyone else reviewing the modified code to determine exactly what changes were made.